#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Author : GUO Lin 
#
# Created on 2010-05-18.
# $Id$
#

import os

import unittest

from urlparse import urlsplit, urlunsplit
from google.appengine.api import apiproxy_stub_map
from google.appengine.api import datastore_file_stub
from google.appengine.api import mail_stub
from google.appengine.api import urlfetch_stub
from google.appengine.api import user_service_stub
from google.appengine.api.memcache import memcache_stub

from django.http import QueryDict
from django.test.client import Client
from django.utils.encoding import smart_str

from freeconnect import users

import friday

ANONYMOUS     = ""
LOGGED_USER   = "guolin.mobi@gmail.com"
WEBMASTER     = "heavyzheng@gmail.com"


class TestBase(unittest.TestCase):

    APPID = "vive-le-vendredi"
    
    FORM_ERROR_COMPULSORY_FIELD = "This field is required."
    FORM_ERROR_INVALID_URL  = "Enter a valid URL." 
    
    RIGHT_ERROR = "Current user cannot"
    
    def setUp(self):
        self.clear_django()
        self.client = Client() 

    def tearDown(self):
        #
        pass

    def _reset_current_user(self, email, is_admin=False):
        os.environ["USER_EMAIL"] = email
        if is_admin:
            os.environ["USER_IS_ADMIN"] = "1"
        else:
            os.environ["USER_IS_ADMIN"] = "0"

    @classmethod
    def webmaster_email(cls):
        return WEBMASTER
    
    @classmethod
    def logged_email(cls):
        return LOGGED_USER
    
    @classmethod
    def anonymous_email(cls):
        return ANONYMOUS

    def reset_user_to_webmaster(self):
        self._reset_current_user(self.__class__.webmaster_email())
    
    def reset_user_to_logged(self):
        self._reset_current_user(self.__class__.logged_email())

    def reset_user_to_anonymous(self):
        self._reset_current_user(self.__class__.anonymous_email())

    @classmethod
    def get_current_user(cls):
        return users.get_current_user(request=None)

    @classmethod
    def get_user(cls, email):
        return users.get_user(email, create=True)

    def clear_django(self, user_email=WEBMASTER):
        # Start with a fresh api proxy.  
        apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
        
        # Use a fresh stub datastore.
        # From this point on in the tests, all calls to the Data Store, such as get and put,
        # will be to the temporary, in-memory datastore stub. 
        stub = datastore_file_stub.DatastoreFileStub(TestBase.APPID, '/dev/null', '/dev/null')
        apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub) 
   
        # Use a fresh stub UserService.
        apiproxy_stub_map.apiproxy.RegisterStub('user', user_service_stub.UserServiceStub())
        os.environ['AUTH_DOMAIN'] = 'gmail.com'
        os.environ['USER_EMAIL'] = user_email # set to '' for no logged in user
        os.environ['SERVER_NAME'] = 'testserver'
        os.environ['SERVER_PORT'] = '80'
        os.environ['USER_IS_ADMIN'] = '1'     #admin user 0 | 1
        os.environ['APPLICATION_ID'] = TestBase.APPID
      
        # Use a fresh urlfetch stub.
        apiproxy_stub_map.apiproxy.RegisterStub('urlfetch', urlfetch_stub.URLFetchServiceStub())

        #User a memcache stub
        apiproxy_stub_map.apiproxy.RegisterStub('memcache', memcache_stub.MemcacheServiceStub())

        #Use a fresh mail stub. 
        #mail stub have a conflit with the other api by now in the real gae environment. 
        #so comment it.
        apiproxy_stub_map.apiproxy.RegisterStub('mail', mail_stub.MailServiceStub())

    def assertContains(self, response, text, count=None, status_code=200):
        """
        Asserts that a response indicates that a page was retrieved
        successfully, (i.e., the HTTP status code was as expected), and that
        ``text`` occurs ``count`` times in the content of the response.
        If ``count`` is None, the count doesn't matter - the assertion is true
        if the text occurs at least once in the response.
        """
        self.assertEqual(response.status_code, status_code,
            "Couldn't retrieve page: Response code was %d (expected %d)'" %
                (response.status_code, status_code))
        text = smart_str(text, response._charset)
        real_count = response.content.count(text)
        if count is not None:
            self.assertEqual(real_count, count,
                "Found %d instances of '%s' in response (expected %d)" %
                    (real_count, text, count))
        else:
            self.failUnless(real_count != 0,
                            "Couldn't find '%s' in response" % text)

                            
    def assertRedirects(self, response, expected_url, status_code=302,
                        target_status_code=200, host=None):
        """Asserts that a response redirected to a specific URL, and that the
        redirect URL can be loaded.

        Note that assertRedirects won't work for external links since it uses
        TestClient to do a request.
        """
        if hasattr(response, 'redirect_chain'):
            # The request was a followed redirect
            self.failUnless(len(response.redirect_chain) > 0,
                ("Response didn't redirect as expected: Response code was %d"
                " (expected %d)" % (response.status_code, status_code)))

            self.assertEqual(response.redirect_chain[0][1], status_code,
                ("Initial response didn't redirect as expected: Response code was %d"
                 " (expected %d)" % (response.redirect_chain[0][1], status_code)))

            url, status_code = response.redirect_chain[-1]

            self.assertEqual(response.status_code, target_status_code,
                ("Response didn't redirect as expected: Final Response code was %d"
                " (expected %d)" % (response.status_code, target_status_code)))

        else:
            # Not a followed redirect
            self.assertEqual(response.status_code, status_code,
                ("Response didn't redirect as expected: Response code was %d"
                 " (expected %d)" % (response.status_code, status_code)))

            url = response['Location']
            scheme, netloc, path, query, fragment = urlsplit(url)

            redirect_response = response.client.get(path, QueryDict(query))

            # Get the redirection page, using the same client that was used
            # to obtain the original response.
            self.assertEqual(redirect_response.status_code, target_status_code,
                ("Couldn't retrieve redirection page '%s': response code was %d"
                 " (expected %d)") %
                     (path, redirect_response.status_code, target_status_code))

        e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url)
        if not (e_scheme or e_netloc):
            expected_url = urlunsplit(('http', host or 'testserver', e_path,
                e_query, e_fragment))

        self.assertEqual(url, expected_url,
            "Response redirected to '%s', expected '%s'" % (url, expected_url))

            
            
# EOF
